﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MC_AI_002
{
    // goes through the entire group's tracklist starting from one location and finds all singly contained groups, then returns them all

    //
    static class TrackIterator
    {
        /*  returns an array of Track lists that correspond to all individual and non-connected paths along the track
         *  parameters:
         *      original : The original TrackGroup that is going to be looked through
         *      references: The neighboring Track pieces of the one that was remove just before this is called
         */


        // Currently in an infinite loop. Fix on Friday
        // UPDATE ON PROGRESS: Finished, needs refinement later; decently fast currently
        // RE: UPDATE -- Not quite finished, not recognizing that the number of members is changing in each group
        // RE: RE: UPDAte -- Seems to work fine for now
        static public List<Track>[] findBrokenPaths(TrackGroup original, Track[] references)
        {
            List<List<Track>> finalList = new List<List<Track>>();
            List<Track> skip = new List<Track>(); // holds a skip list to make sure that the same path isn't iterate over more than once
            
            int numSubLists = -1;

            int numIt;
            int MaxIt = 30;

            // start with one reference and continue until the last reference has been checked
            foreach (Track worker in references)
            {
                numIt = 0;
                // if skippable list isn't empty, check to see if current worker is in it
                if (skip.Count > 0)
                {
                    if (skip.Contains(worker)){
                        continue;
                    }
                }
                // populate open list
                List<Track> open = new List<Track>();
                int[] n_List = worker.getNeighbors();
                foreach(int n in n_List){
                    open.Add(original.getTrackByID(n));
                }

                // initialize closed list to just the worker
                List<Track> closed = new List<Track>();
                closed.Add(worker);

                // now iterate through the now populated open list for as long as there are pieces within the open list
                bool end = false;

                while (!end){ // end will == true when open list has no objects within
                    // get new options for open list from neighbors of current open list
                    List<Track> add = new List<Track>();
                    foreach(Track o in open){
                        if (o != null)
                        {
                            n_List = o.getNeighbors();
                            foreach (int n in n_List)
                            {
                                add.Add(original.getTrackByID(n));
                            }
                        }
                    }
                    // send all open Tracks to the remove list
                    List<Track> remove = new List<Track>();
                    foreach(Track o in open){
                        remove.Add(o);
                    }
                    // now remove
                    foreach(Track r in remove){
                        open.Remove(r);
                        closed.Add(r);
                    }
                    // clear remove
                    remove.Clear();

                    // add the new options from add to open list
                    foreach(Track a in add){
                        open.Add(a);
                    }
                    // clear add
                    add.Clear();
                    
                    // check to see if current open list contains a reference Track
                    foreach(Track r in references){
                        if (open.Contains(r)){
                            skip.Add(r);
                        }
                    }

                    // now make sure that if closed has an item then it cannot be in open
                    foreach (Track c in closed)
                    {
                        if (open.Contains(c))
                        {
                            open.Remove(c);
                        }
                    }

                    // now finally check to see if there are no Tracks in the open list
                    if (open.Count == 0)
                    {
                        end = true;
                    }
                    numIt++;

                    if (numIt >= MaxIt)
                    {
                        end = true;
                    }
                    
                    /* Debug code, not really necesary right now
                    printList(closed, "Closed");
                    printList(open, "Open");
                    printList(remove, "Remove");
                    printList(add, "Add");
                    Console.WriteLine("Size of Open = {0}", open.Count);
                    
                    Console.ReadKey();
                    Console.Clear();
                     */
                }

                numSubLists++;
                finalList.Add(new List<Track>());

                foreach (Track c in closed)
                {
                    finalList.ElementAt(numSubLists).Add(c);
                }

            }
            if (numSubLists >= 0){
                return finalList.ToArray();
            }
            return null; // worst case scenario, should not happen!
        }

        static private void printList(List<Track> list, string name)
        {
            Console.WriteLine("{0}", name);

            foreach (Track T in list)
            {
                Console.WriteLine("\tTrack[{0}] is in list", T.getID());
            }

            
        }
        
    }
}
